#pragma once
//导出的多线程，让程序可以真多线程执行代码
#include "Event.h"
#include "ThreadNames.h"
#include "ThreadBody.h"
#include "Platform/PlatformAPI.h"

namespace BattleFire {
	extern int32 GRenderThreadPollPeriodMs;
	struct RenderThreadStatics
	{
		static std::atomic<ENamedThreads> RenderThread;
		static std::atomic<ENamedThreads> RenderThread_Local;

		static ENamedThreads GetRenderThread()
		{
			return RenderThread.load();
		}
		static ENamedThreads GetRenderThread_Local()
		{
			return RenderThread_Local.load();
		}
		static void SetRenderThread(ENamedThreads Thread)
		{
			RenderThread=Thread;
		}
		static void SetRenderThread_Local(ENamedThreads Thread)
		{
			RenderThread_Local=Thread;
		}
	};
	FORCEINLINE ENamedThreads GetRenderThread()
	{
		return RenderThreadStatics::RenderThread.load(std::memory_order_relaxed);
	}

	FORCEINLINE ENamedThreads GetRenderThread_Local()
	{
		return RenderThreadStatics::RenderThread_Local.load(std::memory_order_relaxed);
	}

	FORCEINLINE void SetRenderThread(ENamedThreads Thread)
	{
		RenderThreadStatics::RenderThread.store(Thread,std::memory_order_relaxed);
	}

	FORCEINLINE void SetRenderThread_Local(ENamedThreads Thread)
	{
		RenderThreadStatics::RenderThread_Local.store(Thread,std::memory_order_relaxed);
	}
	extern int32 bHasBackgroundThreads; 
	extern int32 bHasHighPriorityThreads;
	FORCEINLINE ENamedThreads GetThreadIndex(ENamedThreads ThreadAndIndex)
	{
		return (((int32)ThreadAndIndex & (int32)ENamedThreads::ThreadIndexMask) == (int32)ENamedThreads::AnyThread) ? ENamedThreads::AnyThread : ENamedThreads((int32)ThreadAndIndex & (int32)ENamedThreads::ThreadIndexMask);
	}
	FORCEINLINE int32 GetQueueIndex(ENamedThreads ThreadAndIndex)
	{
		return ((int32)ThreadAndIndex & (int32)ECommandQueue::QueueIndexMask) >> (int32)ECommandQueue::QueueIndexShift;
	}
	FORCEINLINE int32 GetTaskPriority(ENamedThreads inThreadAndIndex)
	{
		return ((int32)inThreadAndIndex & (int32)ETaskPriorities::TaskPriorityMask) >> (int32)ETaskPriorities::TaskPriorityShift;
	}
	FORCEINLINE int32 GetThreadPriorityIndex(ENamedThreads inThreadAndIndex)
	{
		int32 Result = ((int32)inThreadAndIndex & (int32)EThreadPriorities::ThreadPriorityMask) >> (int32)EThreadPriorities::ThreadPriorityShift;
		return Result;
	}
	FORCEINLINE ENamedThreads SetPriorities(ENamedThreads ThreadAndIndex, ENamedThreads ThreadPriority, ENamedThreads TaskPriority)
	{
		return ENamedThreads((int32)ThreadAndIndex | (int32)ThreadPriority | (int32)TaskPriority);
	}
	FORCEINLINE ENamedThreads SetPriorities(ENamedThreads ThreadAndIndex, int32 PriorityIndex, bool bHiPri)
	{
		return ENamedThreads((int32)ThreadAndIndex | (PriorityIndex << (int32)EThreadPriorities::ThreadPriorityShift) | (bHiPri ? (int32)ETaskPriorities::HighTaskPriority : (int32)ETaskPriorities::NormalTaskPriority));
	}
	FORCEINLINE ENamedThreads SetThreadPriority(ENamedThreads ThreadAndIndex, ENamedThreads ThreadPriority)
	{
		return ENamedThreads((int32)ThreadAndIndex | (int32)ThreadPriority);
	}
	FORCEINLINE ENamedThreads SetTaskPriority(ENamedThreads ThreadAndIndex, ENamedThreads TaskPriority)
	{
		return ENamedThreads((int32)ThreadAndIndex | (int32)TaskPriority);
	}
	class WorkerThread
	{
		static uint32 TlsSlot;
	public:
		static uint32 GameThreadID;
		static uint32 RenderThreadID;
		static uint32 AudioThreadID;
		static uint32 GetTlsSlot();
		static WorkerThread* GetWorkerThread()
		{
			WorkerThread* workerThread = (WorkerThread*)FPlatformTLS::GetTlsValue( TlsSlot );
			return workerThread;
		}
		static WorkerThread* Create(const char * inName,ThreadBody* inThreadBody);
		
		void Entry();
		virtual bool Kill( bool bShouldWait = true );
		virtual void WaitForCompletion();
		const std::thread::id GetThreadID() const
		{
			return mThreadID;
		}
		WorkerThread(const char *inName);
		virtual ~WorkerThread();

	protected:
		virtual bool CreateInternal(ThreadBody* inThreadBody);
		void SetTls();
		void FreeTls();
		ThreadBody* mThreadBody;
		BattleFireEvent* mThreadInitSyncEvent;
		std::thread *mThread;
		std::thread::id mThreadID;
		char mThreadName[64];
	private:
		virtual void PostCreate() {};
	};
}